﻿// Jinx AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Core
{
    public delegate bool BinaryPredicate<T>(T t1, T t2);

    public static class Util
    {
        public static IEnumerable<T> Singleton<T>(this T t)
        {
            yield return t;
        }

        public static IEnumerable<T> ConcatAll<T>(this IEnumerable<IEnumerable<T>> Enumerables)
        {
            foreach (var e in Enumerables)
                foreach (var i in e)
                    yield return i;
        }

        public static IEnumerable<T> UpToFirst<T>(this IEnumerable<T> E, Func<T, bool> Pred)
        {
            foreach (var e in E)
            {
                yield return e;
                if (Pred(e))
                    break;
            }
        }

        public static string Join<T>(this IEnumerable<T> Seq, string Separator)
        {
            return string.Join(Separator, (from e in Seq select e.ToString()).ToArray());
        }

        public static void WriteAll<T>(this TextWriter Writer, IEnumerable<T> Seq)
        {
            foreach (var i in Seq)
                Writer.WriteLine(i);
        }

        public static IEnumerable<T> ConcatIfNotNull<T>(this IEnumerable<T> Seq, T Item)
        {
            foreach (var I in Seq) yield return I;

            if (Item != null)
                yield return Item;
        }

        public static IEnumerable<T> Concat<T>(this IEnumerable<T> Seq, T Item)
        {
            return Seq.Concat(Item.Singleton());
        }

        public static IEnumerable<T> Map<T>(this IEnumerable<T> Seq, IDictionary<T, T> Map)
        {
            foreach (var t in Seq)
            {
                T Mapped;

                if (Map.TryGetValue(t, out Mapped))
                    yield return Mapped;
                else
                    yield return t;
            }
        }

        public static bool SequenceEqual<T>(this IEnumerable<T> This, IEnumerable<T> That, Func<T, T, bool> Predicate)
        {
            var ThisEnum = This.GetEnumerator();
            var ThatEnum = That.GetEnumerator();

            bool ThisMore, ThatMore;

            while (Move(ThisEnum, out ThisMore, ThatEnum, out ThatMore))
                if (Predicate(ThisEnum.Current, ThatEnum.Current) == false)
                    return false;

            return ThisMore == ThatMore;
        }

        public static void CoEnumerate<T1, T2>(IEnumerable<T1> Enum1, IEnumerable<T2> Enum2, Action<T1, T2> Visitor)
        {
            var Iter1 = Enum1.GetEnumerator();
            var Iter2 = Enum2.GetEnumerator();

            bool More1, More2;

            while (Move(Iter1, out More1, Iter2, out More2))
                Visitor(Iter1.Current, Iter2.Current);
        }

        private static bool Move(IEnumerator ThisEnum, out bool ThisMore, IEnumerator ThatEnum,
                                 out bool ThatMore)
        {
            ThisMore = ThisEnum.MoveNext();
            ThatMore = ThatEnum.MoveNext();

            return ThisMore && ThatMore;
        }
    }
}